/**
 * Created by XHL on 2022-07-26.
 */

#include <Tank.h>

using namespace meta;
using namespace meta::Enum;

namespace entity {
	Tank::Tank(const PInfo &info) : GameObject(info) {

		this->display_self(info.location);
		this->m_movable = true;
		/** set env, aka the observers */
		this->e_game = nullptr;
		this->e_map = nullptr;
		this->e_opponent = nullptr;
	}

	void Tank::try_to_move(const int &ascii) {
		if (!this->m_movable) return;
		/** Some fancy calculation */
		int index = ascii % 12;
		Direction directions[] = {
				D_UP,
				D_LEFT,
				D_NONE,
				D_LEFT,
				D_RIGHT,
				D_RIGHT,
				D_DOWN,
				D_NONE,
				D_DOWN,
				D_NONE,
				D_NONE,
				D_UP
		};
		bool moved = this->move(directions[index], 1);
		if (moved) this->notify();
		this->print_message(ascii);
	}

	void Tank::response() {
		// std::cout << "AI opponent responding";
	}

	[[nodiscard]] bool Tank::is_movable() const &{
		return this->m_movable;
	}

	void Tank::set_movable(const bool &movable) {
		this->m_movable = movable;
	}

	[[nodiscard]] const Location &Tank::get_location() const {
		return this->m_info.location;
	}

	void Tank::print_message(const int &key) const {
		handle::set_cursor_location({ 0, 2 });
		std::cout << "game_round = " << global::game_round;

		handle::set_cursor_location(this->m_info.msg_shift);
		std::string value;
		value.append(1, (char)(key - 32));
		if (key == 72) value = "  Up ";
		if (key == 80) value = " Down";
		if (key == 75) value = " Left";
		if (key == 77) value = "Right";
		std::cout << this->m_info.color
				  << " " << this->m_info.name
				  << " pressed [" << value << "], ";
		printf("location: (%2d, %2d)", this->m_info.location.get_x(), this->m_info.location.get_y());
		std::cout << ", hp = " << this->m_info.hp << "\033[0m";
	}

	void Tank::set_game(Environment *eGame) {
		this->e_game = eGame;
	}

	void Tank::set_map(Environment *eMap) {
		this->e_map = eMap;
	}

	void Tank::set_opponent(Environment *eOpponent) {
		this->e_opponent = eOpponent;
	}

	const PInfo &Tank::get_info() const {
		return this->m_info;
	}

	void Tank::set_hp(int _hp) {
		this->m_info.hp = _hp;
	}

	const int &Tank::get_hp() const {
		return this->m_info.hp;
	}

	void Tank::notify() {
		this->set_movable(false);
		global::game_round += 1;
		this->e_game->response();
		this->e_map->response();
		if (this->e_opponent)this->e_opponent->response();
	}
}